package com.githan.bootsecurity.config;

import com.githan.bootsecurity.service.UserDetailServiceImp;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * @author https://github.com/Han56
 * @date 2021/4/8 14:44
 */
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;

    @Autowired
    private MyAuthenticationFailureHandler myAuthenticationFailureHandler;

    @Autowired
    private MyAuthenticationEntryPoint myAuthenticationEntryPoint;

    @Autowired
    private MyAccessDeniedHandler myAccessDeniedHandler;

    /**
     * 注销操作处理器
     */
    @Autowired
    private MyLogoutHandler myLogoutHandler;

    /**
     * 注销成功处理器
     */
    @Autowired
    private MyLogoutSuccessHandler myLogoutSuccessHandler;
    //注入账户被踢下线处理器
    private MyExpiredSessionStrategy myExpiredSessionStrategy;

//    seesion过期处理器
    private MyInvalidSessionStrategy myInvalidSessionStrategy;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //以下是动态代码权限
        auth.userDetailsService(userDetailsService)
                .passwordEncoder(passwordEncoder);
        //以下是静态权限代码
//        auth.inMemoryAuthentication()
//                .withUser("user")
//                .password(passwordEncoder.encode("123"))
//                .roles("user")
//                .and()
//                .withUser("admin")
//                .password(passwordEncoder.encode("123"))
//                .roles("admin")
//                //配置加密方式
//                .and()
//                .passwordEncoder(passwordEncoder);
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        super.configure(web);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //开启httpBasic认证
//        http.httpBasic()
//                .and()
//                .authorizeRequests()
//                .anyRequest()
//                .authenticated();
        //使用formLogin模式登录（因为HttpBasic不常用）
        //任何请求都需要被认证，所有的请求都会被拦截，包括登录以及其他html，但是要放行login.html，否则就会一直在登录页面死循环
        http.authorizeRequests()
                .antMatchers("/login","/login.html").permitAll()
                .antMatchers("/users","/roles")
                .hasAnyAuthority("ROLE_hysk","ROLE_admin")
                .antMatchers("/menus","/others")
                .hasAnyRole("admin")
                .anyRequest()
                .authenticated()
                .and()
                .logout().permitAll()
                .addLogoutHandler(myLogoutHandler)
                .logoutSuccessHandler(myLogoutSuccessHandler)
                //注销后删除cookie
                .deleteCookies("JSESSIONID")
                .and()
                //设置登录页(替代默认的登陆页面)
                .formLogin().loginPage("/login.html")
                //设置form表单的登录控制器（默认是login）设置表单的action
                .loginProcessingUrl("/login")
                .usernameParameter("username")
                .passwordParameter("password")
//                .defaultSuccessUrl("/home").permitAll()
//                .failureUrl("/login/error");
                //动态设置登录成功处理
                .successHandler(myAuthenticationSuccessHandler)
                //动态设置登录失败处理
                .failureHandler(myAuthenticationFailureHandler)
                .and()
                .exceptionHandling()
                .accessDeniedHandler(myAccessDeniedHandler)
                .authenticationEntryPoint(myAuthenticationEntryPoint)
                .and()
                //无状态的，任何时候都不会使用session
                .sessionManagement()
                //设置最多只能一个用户在线
                .maximumSessions(1)
                .maxSessionsPreventsLogin(false)
                .expiredSessionStrategy(myExpiredSessionStrategy);

        //关闭跨域攻击
        http.csrf().disable();
    }
}
